package br.com.iswe.core.web;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.application.FacesMessage;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.model.SelectItem;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.web.jsf.FacesContextUtils;

import br.com.iswe.core.exp.ISWEConfigurationException;
import br.com.iswe.core.exp.ISWEException;
import br.com.iswe.core.exp.ISWEExceptionHandler;
import br.com.iswe.core.web.util.CheckItensList;

/**
 * ISWE - Project
 * 
 * @author Rafael Noronha
 *
 */
@SuppressWarnings("unchecked")
public class BaseWBean {
	public static final String DETALHAR_CONSULTA_FILTRO_VAZIO = "wbean.detalhar.consulta.filtro.vazio";
	public static final String SALVAR_ESTADO_INVALIDO = "wbean.salvar.estado.invalido";
	public static final String PASTA_UPLOADS = "/uploads";
	public static final String SEPARADOR = "/";
	
	private static final Log log = LogFactory.getLog(BaseWBean.class);
	
	private ResourceBundle rb = null;
	
	public BaseWBean(){
		rb = ResourceBundle.getBundle("wbean", getContext().getExternalContext().getRequestLocale());
	}
	
	/**
	 * Cria uma lista de CheckItensList.
	 * @param objetos
	 * @return
	 */
	protected List<CheckItensList> buildCheckItensList(List objetos) {
		List<CheckItensList> retorno = new ArrayList<CheckItensList>(objetos.size());
		//Varre a lista de objetos
		for (Serializable obj : (List<Serializable>)objetos) {
			//cria uma instancia de  CheckItensList e adiciona na lista.
			retorno.add(new CheckItensList(obj));
		}
		return retorno;
	}
	
	/**
	 * M�todo utilit�rio que transforma uma lista de beans em uma lista de SelectItem
	 * necess�rio para criar componentes como Combo, Listas de CheckBOx e etc.
	 * @param dados
	 * @param propValue
	 * @param propLabel
	 * @return
	 */
	protected List<SelectItem> buildSelectItemList(List dados, String propLabel){
		List<SelectItem> retorno = new ArrayList<SelectItem>(dados.size());
		try{
			//Varre os beans
			for (Object bean : dados) {
				//Obtendo o label
				Method mth = BeanUtils.getPropertyDescriptor(bean.getClass(), propLabel).getReadMethod();
				Object label = mth.invoke(bean, new Object[]{});
				
				SelectItem selItem = new SelectItem(bean, label.toString());
				retorno.add(selItem);
			}
		}
		catch(Exception exp){
			addErrorMessage("Erro ao criar a lista de Itens : " + exp.getMessage());
		}
		return retorno;
	}
	
	protected void addErrorMessage(String message) {
		addErrorMessage(message, true);
	}
	
	protected void addErrorMessage(ISWEException isExp) {
		//Obt�m o locale do usu�rio.
		Locale locale = getContext().getExternalContext().getRequestLocale();
		List<String> mensagens = ISWEExceptionHandler.getInstance().getMessages(isExp, locale);
		if(log.isDebugEnabled() && mensagens != null){
			log.debug("[addErrorMessage()] Erros que serao mostrados na tela : " + mensagens.toString(), isExp);
		}
		for (String msg : mensagens) {
			addErrorMessage(msg, false);
		}
	}
	
	/**
	 * M�todo utilit�rio para adi��o de mensagens de erro no request.
	 * @param message
	 * @param isKey
	 */
	protected void addErrorMessage(String message, boolean isKey) {
		if (!isKey) {
			FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message);
			getContext().addMessage(null, facesMsg);
		}
		else{
			String m = rb.getString(message);
			FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, m, m);
			getContext().addMessage(null, facesMsg);
		}
	}

	/**
	 * M�todo utilit�rio para adi��o de mensagens informativas no request.
	 * @param message
	 * @param isKey
	 */
	protected void addInfoMessage(String message, boolean isKey) {
		FacesMessage facesMsg = null;
		if (!isKey) {
			facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, message, message);
			getContext().addMessage(null, facesMsg);
		}
		else{
			String m = rb.getString(message);
			facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, m, m);
			getContext().addMessage(null, facesMsg);
		}
	}
	
	/**
	 * Da um forward para um view id conhecido do faces.
	 * @param viewId
	 */
	protected void forward(String viewId){
	    ViewHandler viewHandler = getApplication().getViewHandler();
	    FacesContext facesCtx = getContext();
	    UIViewRoot view = viewHandler.createView(facesCtx, viewId);
	    facesCtx.setViewRoot(view);
	    facesCtx.renderResponse();
	}

	private Application application = null;
	
	/**
	 * Obt�m o objeto Application.
	 * @return
	 */
	protected Application getApplication(){
		if (application == null){
			ApplicationFactory appFactory = (ApplicationFactory)FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
			application = appFactory.getApplication();
	    }
	    return application;
	}
	
	/**
	 * Obt�m o contexto do Faces.
	 * @return
	 */
	protected FacesContext getContext() {
		return FacesContext.getCurrentInstance();
	}
	
	protected HttpServletRequest getHttpRequest(){
		return (HttpServletRequest)getContext().getExternalContext().getRequest();
	}
	
	protected HttpServletResponse getHttpResponse(){
		return (HttpServletResponse)getContext().getExternalContext().getResponse();
	}
	
	protected ServletContext getServletContext(){
		HttpServletRequest request = getHttpRequest(); 
		if(request != null){
			return request.getSession().getServletContext();
		}
		return null;
	}
    
	protected BeanFactory getBeanFactory(){
		return FacesContextUtils.getRequiredWebApplicationContext(getContext());
	}
	
	protected Timestamp mergeDataEHora(Date data, Timestamp hora){
		java.util.Calendar calendarData = Calendar.getInstance();
		if(data != null){
			calendarData.setTime(data);
		}
		//verifica se existe a hora ja foi setada
		if(hora != null){
			java.util.Calendar calendarHora = Calendar.getInstance();
			calendarHora.setTimeInMillis(hora.getTime());
			calendarData.set(Calendar.HOUR, calendarHora.get(Calendar.HOUR));
			calendarData.set(Calendar.MINUTE, calendarHora.get(Calendar.MINUTE));
			calendarData.set(Calendar.SECOND, calendarHora.get(Calendar.SECOND));
		}
		return new Timestamp(calendarData.getTimeInMillis());
	}
	private static final SimpleDateFormat timeFmt = new SimpleDateFormat("hh:mm");
	private Converter timestampHoraConverver = new Converter(){

		public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
			if(value == null || "".equals( value )){
				return null;
			}
			
			Calendar calendar = Calendar.getInstance();
			try {
				calendar.setTimeInMillis(timeFmt.parse(value).getTime());
			} catch (ParseException e) {
				throw new ISWEConfigurationException("converter.timestamp.wrong.format", e);
			}
			return new Timestamp(calendar.getTimeInMillis());
		}

		public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException {
			if(value == null){
				return null;
			}
			if(value instanceof String){
				return (String)value; 
			}
			if(!(value instanceof Timestamp)){
				throw new ISWEConfigurationException("converter.timestamp.wrong");
			}
			Timestamp time = (Timestamp)value;
			return timeFmt.format(time);
		}
		
	};

	/**
	 * Converter utilizado para o combo.
	 */
	public Converter getTimestampHoraConverver(){
		return timestampHoraConverver ;
	}
}
